package jp.ac.waseda.cs.washi.game;

import java.awt.event.KeyEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Calendar;

import jp.ac.waseda.cs.washi.game.ai.*;
import jp.ac.waseda.cs.washi.game.api.GameInfo;
import jp.ac.waseda.cs.washi.game.api.GameInvoker;
import jp.ac.waseda.cs.washi.game.api.Player;
import jp.ac.waseda.cs.washi.game.api.PlayerAction;
import jp.ac.waseda.cs.washi.game.player.GameRunner;
import jp.ac.waseda.cs.washi.game.scene.ContestScene;
import jp.ac.waseda.cs.washi.game.scene.StartScene;
import jp.ac.waseda.cs.washi.game.scene.UserScene;
import jp.ac.waseda.cs.washi.gameaiarena.gui.JGameWindow;
import jp.ac.waseda.cs.washi.gameaiarena.gui.Renderer;
import jp.ac.waseda.cs.washi.gameaiarena.key.AwtKeyMemorizer;
import jp.ac.waseda.cs.washi.gameaiarena.key.MappedInputer;
import jp.ac.waseda.cs.washi.gameaiarena.runner.AbstractRunner;
import jp.ac.waseda.cs.washi.gameaiarena.scene.Scene;
import jp.ac.waseda.cs.washi.gameaiarena.scene.SceneManager;

public class Starter {
	private Starter() {
	}

	public static void start(Player player1, Player player2, int mapIndex,
			int titleTime, int roundTime, double fps,
			boolean playingUser, boolean limittingTime,
			boolean ingoringException, boolean recording, String replayFileName) {
		// フレームの作成
		JGameWindow window = new JGameWindow("JavaChallenge 2011 Summer");
		Renderer renderer = window.showAtCenter(1400, 540);
		final SceneManager<GameEnvironment> sceneManager = new SceneManager<GameEnvironment>(
				fps);
		MappedInputer inputer = new MappedInputer();

		// initialize environment
		GameEnvironment env = new GameEnvironment(sceneManager, renderer,
				inputer);

		window.addWindowListenerOfTerminateSceneManager(sceneManager);

		Scene<GameEnvironment> nextScene;
		nextScene = createNextScene(env, player1, player2, mapIndex,
				roundTime, playingUser, limittingTime, ingoringException,
				recording, replayFileName);

		sceneManager.run(env, new StartScene(nextScene, titleTime));
		window.dispose();
		System.exit(0);
	}

	private static Scene<GameEnvironment> createNextScene(GameEnvironment env,
			Player player1, Player player2, int mapIndex,
			int roundTime, boolean playingUser,
			boolean limittingTime, boolean ingoringException, boolean recording, String replayFileName) {
		Scene<GameEnvironment> nextScene;
		if (playingUser) {
			setInputer(env);
			nextScene = new UserScene();
		} else {
			ObjectInputStream ois = null;
			ObjectOutputStream oos = null;
			if (recording) {
				oos = openOutputStream(player1, player2, oos);
				try {
					oos.writeObject(mapIndex);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (replayFileName != null) {
				ois = openInputStream(replayFileName, ois);
				try {
					mapIndex = (Integer)ois.readObject();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
			AbstractRunner<GameInfo, PlayerAction, Player> runner1 = GameRunner
					.create(player1, limittingTime, ingoringException, ois, oos);
			AbstractRunner<GameInfo, PlayerAction, Player> runner2 = GameRunner
					.create(player2, limittingTime, ingoringException, ois, oos);
			nextScene = new ContestScene(runner1, runner2, mapIndex, roundTime);
		}
		return nextScene;
	}

	private static void setInputer(GameEnvironment env) {
		MappedInputer inputer = env.getInputer();
		AwtKeyMemorizer keyMemorizer = env.getRenderer().getPanel()
				.getKeyMemorizer();
		int i = 0;
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_RIGHT));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_UP));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_LEFT));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_DOWN));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_SPACE));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_B));

		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_S));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_W));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_A));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_Z));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_Q));
		inputer.add(i++, keyMemorizer.getKeyPressChecker(KeyEvent.VK_E));
	}

	private static ObjectInputStream openInputStream(String replayFileName,
			ObjectInputStream ois) {
		try {
			FileInputStream reader = new FileInputStream(replayFileName);
			ois = new ObjectInputStream(reader);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return ois;
	}

	private static ObjectOutputStream openOutputStream(Player player1,
			Player player2, ObjectOutputStream oos) {
		String nameStr = player1.getClass().getSimpleName() + "-"
				+ player2.getClass().getSimpleName();
		Calendar cal = Calendar.getInstance();
		String dateString = (cal.get(Calendar.MONTH) + 1) + "-"
				+ cal.get(Calendar.DATE) + "-"
				+ cal.get(Calendar.HOUR_OF_DAY) + "-"
				+ cal.get(Calendar.MINUTE);
		String fileName = nameStr + "__" + dateString + ".rep";
		try {
			FileOutputStream writer = new FileOutputStream(fileName);
			oos = new ObjectOutputStream(writer);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return oos;
	}

	public static void startRecord(Player player1, Player player2, int mapIndex) {
		start(player1, player2, mapIndex, 100, 1000, 60.0, false, true, true, true, null);
	}

	public static void startReplay(String fileName) {
		start(null, null, -1, 100, 1000, 30.0, false, false, false, false, fileName);
	}

	public static void main(String[] args) {
		//startReplay("team2-Banshee__6-26-13-10.rep");
		//startReplay("team2-Banshee__6-26-13-13.rep");
		startReplay("team2-Banshee__6-26-13-11.rep");
		
		//startRecord(new team2(), new Banshee(), 2);
		//startRecord(new Banshee(), new team2(), 2);
		//GameInvoker.startForUserPlaying(1);
	}
}
